package cc.telecomdigital.tdstock.Framework.UniqueItem;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.view.Display;
import android.view.WindowManager;

// Screen Orientation Change Portrait, Landscape
// The purpose is to detect the coordinate, even the display has been hardcode to Portrait and Landscape
public class ScreenOrientationChangeListener
{
	public enum SCR_ORIENTATION
	{
		UNKNOWN, PORTRAIT, LANDSCAPE
	}

	// For external usage
	public interface IScreenOrientationChangeListener
	{
		/** Report of Screen Orientation Change **/
		void ScreenOrientation_Response(SCR_ORIENTATION orientation);
	}

	private boolean						debugMode			= false;
	private final String					LOG_TAG		     = "ScreenOrientationChangeListener";

	private Context						hostContext;
	private IScreenOrientationChangeListener	interfaceReport;
	private boolean						isEnabled;
	private SensorManager					sensorManager;
	private SCR_ORIENTATION					orientation;
	private Display                              displayObj;	


	private final Sensor					inputSensor;

	private int							trialIndex		= 0;
	private final int						trialCount		= 3;
	private SCR_ORIENTATION[]				lastOrientation;
	private int                                  sensorType = Sensor.TYPE_ACCELEROMETER;
	private SensorEventListener				evtListener		= new SensorEventListener()
														{
															public void onSensorChanged( SensorEvent event)
															{
																// Get the InitialValue
																if (event.sensor.getType() == sensorType)
																	PerformOrientationChecking(event);
															}

															public void onAccuracyChanged(
																	Sensor sensor, int accuracy)
															{			}
														};

	private float			 OneEightyOverPi	= 57.29577957855f;
	private boolean           isTabletVersion    = false;	

	public void SetTabletVersion(boolean iEnable)
	{
        isTabletVersion = iEnable;
	}
	
	private void PerformOrientationChecking(SensorEvent iEvent)
	{
		int index, finalCount;
		SCR_ORIENTATION calValue;
		
//		if (iEvent.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
//			return;

		//Get the orientation based on current info
		calValue = CalculateOrientation(iEvent.values);
		if (debugMode)
			TDStockLog.i(LOG_TAG, "Update Value=" + calValue);
		//comparised with the last three result
		if (trialIndex < trialCount)
		{
			lastOrientation[trialIndex] = calValue;
			++trialIndex;
			return;
		}

		finalCount = trialCount -1;
		// Re-Order the orientation
		for (index = 0; index < finalCount; index++)
			lastOrientation[index] = lastOrientation[index + 1];

		lastOrientation[finalCount] = calValue;
		// Get the common answer, calValue is
		// already assigned as the last
		for (index = 0; index < finalCount; index++)
		{
			if (calValue != lastOrientation[index])
				return;
		}

		// Prevent for duplicate
		if (calValue == orientation)
			return;

		orientation = calValue;
		
		// Try to et the current orientation
		if (interfaceReport != null)
			interfaceReport.ScreenOrientation_Response(orientation);		
	}

	// Need a fast calculation
	private SCR_ORIENTATION CalculateOrientation(float[] iCoordinates)
	{
		float  X, Y, Z;
		float  magnitude;
		//Use Table Option
		if (isTabletVersion)
		{
          	X = -iCoordinates[1];
          	Y = -iCoordinates[0];
		}
		else
		{
          	X = -iCoordinates[0];
          	Y = -iCoordinates[1];
		}
     	Z = -iCoordinates[SensorManager.DATA_Z];

		// Don't trust the angle if the magnitude is small compared to the y
		// value if (magnitude * 4 >= Z*Z)
		// control the sensitivity of tilting
     	magnitude = X * X + Y * Y;
		if (magnitude * 8 >= Z * Z)
		{
			int   orientation;			
			float angle = (float) Math.atan2(-Y, X) * OneEightyOverPi;

			orientation = 90 - (int) Math.round(angle);
			// normalize to 0 - 359 range
			// normalize to 0 - 359 range
			while (orientation < 0)
				orientation += 360;
			
			orientation %= 360;
			
			if ((orientation < 300) && (orientation > 220))
				return SCR_ORIENTATION.LANDSCAPE;

			return SCR_ORIENTATION.PORTRAIT;
		}
		return SCR_ORIENTATION.UNKNOWN;
	}

	/** Register to use the broadcast receiver for screen orientation **/
	public ScreenOrientationChangeListener(Context iHostContext,
			IScreenOrientationChangeListener iReportInterface)
	{
		if (debugMode)
			TDStockLog.i(LOG_TAG, "Create a New Receiver");

		hostContext = iHostContext;
		isEnabled = false;
		interfaceReport = iReportInterface;
		orientation = SCR_ORIENTATION.UNKNOWN;
		trialIndex = 0;
		lastOrientation = new SCR_ORIENTATION[trialCount];
		// Only belong to this Context
		sensorManager = (SensorManager) iHostContext
				.getSystemService(Activity.SENSOR_SERVICE);
		// A null sensor will come if the sensor does not exist
		inputSensor = sensorManager.getDefaultSensor( sensorType);	
		displayObj  = ((WindowManager)hostContext.getSystemService(Activity.WINDOW_SERVICE)).getDefaultDisplay();	
	}

	/** Ask if we are using the detector **/	
	public boolean IsEnabled()
	{
		return isEnabled;
	}

	/** Disable the current usage of the Broadcast receiver **/
	public synchronized void Disable()
	{
		if (isEnabled == false)
			return;

		sensorManager.unregisterListener(evtListener);
		isEnabled = false;
		if (debugMode)
			TDStockLog.i(LOG_TAG, "Unregister Receiver");
	}

	/** Enable the Broadcast Receiver
	   ** Re-Register with the system on **/
	public synchronized void Enable()
	{
		if (isEnabled == true)
			return;

		if (inputSensor == null)
		{
			TDStockLog.i(LOG_TAG, "Sensor is not supported on this device");
			return;
		}

		// Get the InitialValue
		if(displayObj.getOrientation() == 1)
		{
			orientation = SCR_ORIENTATION.LANDSCAPE;
			TDStockLog.i(LOG_TAG, "Start Orientation is landscape");			
		}
		else
		{
			orientation = SCR_ORIENTATION.PORTRAIT;
			TDStockLog.i(LOG_TAG, "Start Orientation is portrait");
		}

		sensorManager.registerListener(evtListener, inputSensor,
				SensorManager.SENSOR_DELAY_NORMAL);	
		isEnabled = true;

		if (debugMode)
			TDStockLog.i(hostContext.toString(), "Register Receiver, Width=" + displayObj.getWidth()
					+ ",Height=" + displayObj.getHeight() 
					+ ", Orientation=" + orientation);
	}

	/** Dispose the object **/	
	public void Dispose()
	{
		Disable();
		sensorManager = null;
		if (debugMode)
			TDStockLog.i(LOG_TAG, "Object has been free");
	}

	/** Get Current Screen orientation **/
	public SCR_ORIENTATION GetScreenOrientation()
	{
		return orientation;
	}

	/** Set the debug level to access information display **/	
	public void SetDebugMode(boolean iEnable)
	{
		debugMode = iEnable;
	}
}